package down.sallai.ml.services.github;

import down.sallai.ml.services.ProxyService;
import down.sallai.ml.util.okhttp.GetUtils;
import lombok.extern.slf4j.Slf4j;
import okhttp3.Headers;
import okhttp3.MediaType;
import okhttp3.Response;
import okhttp3.ResponseBody;
import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.*;

/**
 * @ClassName GitHubProxyServiceImpl
 * @Description github网站代理服务
 * @Author sallai
 * @Email sallai@aliyun.com
 * @Date 19:28 2024/2/9
 * @Version 1.0
 **/
@Service
@Slf4j
public class GitHubProxyServiceImpl implements ProxyService {
    @Autowired
    HttpServletResponse response;

    @Autowired
    HttpServletRequest request;

    @Autowired
    GetUtils getUtils;

    @Value("${github.targetURL}")
    public String TARGET_URL;

    @Value("${mydown.domain}")
    private String domain;

    @Override
    public void proxy(String url) {
        url = TARGET_URL + url;
        String xrW = request.getHeader("X-Requested-With");
        Set<String> contain = new HashSet<>();
        contain.add("accept");
        contain.add("accept-encoding");
        contain.add("sec-fetch-site");
        contain.add("cookie");
        Map<String, String> headerMap = getUtils.getRequestHeaderMap(request, contain);
        headerMap.put("X-Requested-With", xrW);
        headerMap.put(":authority", "github.com");
        try {
            Response resp = getUtils.sendGetRequest(url, headerMap);
            getUtils.copyHeaderToResponse(resp, response, this::handlerResponseToClient);
            handlerResponse(Objects.requireNonNull(resp.body()));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 处理响应头逻辑
     *
     * @param name
     * @param value
     * @param resp
     */
    private void handlerResponseToClient(String name, String value, HttpServletResponse resp) {
        Set<String> noContain = new HashSet<>();
        noContain.add("Content-Security-Policy");
        noContain.add("X-Content-Type-Options");
        boolean flag = false;
        for (String no : noContain) {
            if (StringUtils.containsIgnoreCase(name, no)) {
                flag = true;
                break;
            }
        }
        if (flag) return;
        if (StringUtils.containsIgnoreCase(name, "content-type")) {
            resp.setContentType(value);
        } else {
            if (value.contains("github.com")) {
                value = value.replaceAll("github.com", domain);
            }
            resp.addHeader(name, value);
        }
    }


    private void handlerResponse(ResponseBody resp) {
        MediaType mediaType = resp.contentType();
        if (null == mediaType) {
            return;
        }
        String type = mediaType.type();
        switch (type) {
            case "image":
                handlerBin(resp);
                break;
            case "text":
                handlerText(resp);
                break;
            default:
                log.info("default->bin " + type);
                handlerBin(resp);
        }
    }

    private void handlerText(ResponseBody resp) {
        String body = null;
        try {
            body = resp.string();
            body = body.
//                    replaceAll("\"/","\"/github/").
        replaceAll("(?<!\\.)github\\.com", domain);
//                            .replaceAll("\"/","\"/github/");
            PrintWriter writer = response.getWriter();
            writer.print(body);
            writer.flush();
            writer.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void handlerBin(ResponseBody resp) {
        InputStream inputStream = resp.byteStream();
        try {
            ServletOutputStream outputStream = response.getOutputStream();
            // 在http响应中输出流
            byte[] cache = new byte[1024];
            int nRead = 0;
            while ((nRead = inputStream.read(cache)) != -1) {
                outputStream.write(cache, 0, nRead);
                outputStream.flush();
            }
            outputStream.flush();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}
